package top.ieei.demo.tftp;

import java.net.InetAddress;

/**
 * 
 * TFTP 包，抽象类<br>
 * @author xiecongshu
 */
public abstract class TftpPacket
{
    /**
     * 操作码索引位置
     */
    protected static final int INDEX_OPCODE = 0;
    
    /**
     * 最小Packet大小
     */
    public static final int MIN_PACKET_SIZE = 4;
    
    /**
     * 操作码
     */
    public static final int OPCODE = 0;
    
    /**
     * 目的地址
     */
    private InetAddress destAddr;
    
    /**
     * 目的端口
     */
    private int destPort;
    
    /**
     * 取操作码
     * @param tftpBytes
     * @return
     */
    public static int fetchOpCode(byte[] tftpBytes)
    {
        if (null == tftpBytes)
        {
            return 0;
        }
        if (tftpBytes.length < INDEX_OPCODE + 2)
        {
            return 0;
        }
        return byteToInt(tftpBytes[INDEX_OPCODE], tftpBytes[INDEX_OPCODE + 1]);
    }
    
    /**
     * 将两字节转换int
     * @param Hi 高位byte
     * @param Lo 低位byte
     * @return int
     */
    public static int byteToInt(byte Hi, byte Lo)
    {
        return (((int) ((int) Hi << 8) & 0xff00) | ((int) Lo & 0xff));
    }
    
    /**
     * <默认构造函数>
     */
    public TftpPacket()
    {
        
    }
    
    /**
     * 从索引处开始读取，直到读取到的byte等于0，返回读取结束时的索引加1返回，读取到的byte转换字符存储在stringbuffer中
     * @param index 指定开始读取的索引
     * @param b 字节数组
     * @param sb 字符缓冲对象
     * @return int 读取结束时索引加1的值
     */
    public int readStringFromByteArray(int index, byte[] b, StringBuffer sb)
    {
        int i;
        for (i = index; i < b.length; i++)
        {
            // 当读取到0时，结束
            if (b[i] == 0)
                break;
            
            // 将字节转换字符存取在stringbuffer中
            sb.append((char) b[i]);
        }
        return ++i;
    }
    
    /**
     * 根据UDP数据构建TFTP请求包
     * <默认构造函数>
     */
    public TftpPacket(byte[] tftpBytes) throws TftpException
    {
        // 检查UDP数据包中的数据是否满足最小包大小
        if ((tftpBytes == null) || (tftpBytes.length < getMinPacketSize()))
        {
            throw new TftpException(
                    "Argument passed to constructor is not a valid packet!");
        }
        
        // 检查UDP数据包中的数据对应的操作码是否符合要求
        if (byteToInt(tftpBytes[INDEX_OPCODE], tftpBytes[INDEX_OPCODE + 1]) != getOpCode())
        {
            throw new TftpException(
                    "Argument passed to constructor is not a valid  packet!");
        }
    }
    
    /**
     * 抽象方法，获取TFTP包数据
     * @return byte[]
     */
    public abstract byte[] getBytes();
    
    /**
     * 抽象方法，获取操作码
     * @return int
     */
    public abstract int getOpCode();
    
    /**
     * 获取最小TFTP数据请求包大小
     * @return int
     */
    public int getMinPacketSize()
    {
        return MIN_PACKET_SIZE;
    }
    
    /**
     * 设置传输目的地址
     * @param addr void
     */
    public void setAddress(InetAddress addr)
    {
        destAddr = addr;
    }
    
    /**
     * 设置传输通讯端口
     * @param port void
     */
    public void setPort(int port)
    {
        destPort = port;
    }
    
    /**
     * 获取传输目的地址
     * @return InetAddress
     */
    public InetAddress getAddress()
    {
        return destAddr;
    }
    
    /**
     * 
     * 获取传输通讯端口
     * @return int
     */
    public int getPort()
    {
        return destPort;
    }
    
}
